package org.study.memcached.api.util;

import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import net.spy.memcached.*;
import net.spy.memcached.internal.OperationFuture;
import org.study.memcached.api.constant.MemcachedProperties;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.*;
import java.util.concurrent.ExecutionException;

/**
 * 作用描述
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2024年01月12日
 */
@Slf4j
@UtilityClass
public class MemcachedUtils {
    private MemcachedClient getMemcachedClient() throws IOException {
        InetSocketAddress address = new InetSocketAddress(MemcachedProperties.HOST, MemcachedProperties.PORT);
        MemcachedClient memcachedClient = new MemcachedClient(address);
        return memcachedClient;
    }

    public Boolean touch(String key, int exp) throws IOException, ExecutionException, InterruptedException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            OperationFuture<Boolean> touchFuture = memcachedClient.touch(key, exp);
            return touchFuture.get();
        } finally {
            memcachedClient.shutdown();
        }
    }

    /**
     * 用append向已存在的key追加数据
     *
     * @param key   缓存key
     * @param value 要追加的value
     */
    public Boolean append(String key, Object value) throws IOException, ExecutionException, InterruptedException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            OperationFuture<Boolean> appendFuture = memcachedClient.append(key, value);
            return appendFuture.get();
        } finally {
            memcachedClient.shutdown();
        }
    }

    /**
     * 用prepend向已存在的key对应的value前追加数据
     *
     * @param key   缓存key
     * @param value 要追加的value
     */
    public Boolean prepend(String key, Object value) throws IOException, ExecutionException, InterruptedException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            OperationFuture<Boolean> prependFuture = memcachedClient.prepend(key, value);
            return prependFuture.get();
        } finally {
            memcachedClient.shutdown();
        }
    }

    public CASResponse cas(String key, long casId, Object value) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            CASResponse response = memcachedClient.cas(key, casId, value);
            return response;
        } finally {
            memcachedClient.shutdown();
        }
    }

    public CASResponse cas(String key, long casId, int exp, Object value) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            CASResponse response = memcachedClient.cas(key, casId, exp, value);
            return response;
        } finally {
            memcachedClient.shutdown();
        }
    }

    /**
     * 添加数据，如果key已经存在，则返回false，并且不会更新value
     *
     * @param key   缓存key
     * @param exp   过期时间，单位是秒，0表示不过期
     * @param value 缓存value
     */
    public Boolean add(String key, int exp, Object value) throws IOException, ExecutionException, InterruptedException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            OperationFuture<Boolean> addFuture = memcachedClient.add(key, exp, value);
            return addFuture.get();
        } finally {
            memcachedClient.shutdown();
        }
    }

    /**
     * 设置缓存
     *
     * @param key   缓存key
     * @param exp   过期时间，单位是秒，0表示不过期
     * @param value 缓存value
     */
    public Boolean set(String key, int exp, Object value) throws IOException, ExecutionException, InterruptedException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            OperationFuture<Boolean> setFuture = memcachedClient.set(key, exp, value);
            return setFuture.get();
        } finally {
            memcachedClient.shutdown();
        }
    }

    /**
     * 用replace替换已存在的key对应的value
     *
     * @param key   缓存key
     * @param exp   过期时间，单位是秒，0表示不过期
     * @param value 缓存value
     */
    public Boolean replace(String key, int exp, Object value) throws IOException, ExecutionException, InterruptedException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            OperationFuture<Boolean> replaceFuture = memcachedClient.replace(key, exp, value);
            return replaceFuture.get();
        } finally {
            memcachedClient.shutdown();
        }
    }

    public CASValue<Object> getAndTouch(String key, int exp) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            CASValue<Object> casValue = memcachedClient.getAndTouch(key, exp);
            return casValue;
        } finally {
            memcachedClient.shutdown();
        }
    }

    public CASValue<Object> gets(String key) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            CASValue<Object> casValue = memcachedClient.gets(key);
            return casValue;
        } finally {
            memcachedClient.shutdown();
        }
    }

    /**
     * 获取缓存
     *
     * @param key   缓存key
     * @param clazz 缓存值的类型
     */
    public <T> T get(String key, Class<T> clazz) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            Object value = memcachedClient.get(key);
            if (value == null) {
                return null;
            }
            if (clazz.isInstance(value)) {
                return (T) value;
            } else {
                log.warn("数据类型不一致，返回null");
                return null;
            }
        } finally {
            memcachedClient.shutdown();
        }
    }

    public Map<String, Object> getBulk(Iterator<String> keyIter) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            Map<String, Object> getBulk = memcachedClient.getBulk(keyIter);
            return getBulk;
        } finally {
            memcachedClient.shutdown();
        }
    }

    public Map<String, Object> getBulk(Collection<String> keys) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            Map<String, Object> getBulk = memcachedClient.getBulk(keys);
            return getBulk;
        } finally {
            memcachedClient.shutdown();
        }
    }

    public Map<String, Object> getBulk(String... keys) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            Map<String, Object> getBulk = memcachedClient.getBulk(keys);
            return getBulk;
        } finally {
            memcachedClient.shutdown();
        }
    }

    public Map<SocketAddress, String> getVersions() throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            Map<SocketAddress, String> getVersions = memcachedClient.getVersions();
            return getVersions;
        } finally {
            memcachedClient.shutdown();
        }
    }

    public Map<SocketAddress, Map<String, String>> getStats(String arg) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            Map<SocketAddress, Map<String, String>> getStats = memcachedClient.getStats(arg);
            return getStats;
        } finally {
            memcachedClient.shutdown();
        }
    }

    /**
     * 给key增加指定的long值
     *
     * @param key 缓存key
     * @param by  要增加的值
     * @param def key不存在时的默认值
     * @param exp 过期时间，单位是秒，-1表示不过期
     */
    public long incr(String key, long by, long def, int exp) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            long incr = memcachedClient.incr(key, by, def, exp);
            return incr;
        } finally {
            memcachedClient.shutdown();
        }
    }

    /**
     * 给key增加指定的int值
     *
     * @param key 缓存key
     * @param by  要增加的值
     * @param def key不存在时的默认值
     * @param exp 过期时间，单位是秒，-1表示不过期
     */
    public long incr(String key, int by, long def, int exp) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            long incr = memcachedClient.incr(key, by, def, exp);
            return incr;
        } finally {
            memcachedClient.shutdown();
        }
    }

    /**
     * 给key减少指定的long值
     *
     * @param key 缓存key
     * @param by  要减少的值
     * @param def key不存在时的默认值
     * @param exp 过期时间，单位是秒，-1表示不过期
     */
    public long decr(String key, long by, long def, int exp) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            long decr = memcachedClient.decr(key, by, def, exp);
            return decr;
        } finally {
            memcachedClient.shutdown();
        }
    }

    /**
     * 给key减少指定的int值
     *
     * @param key 缓存key
     * @param by  要减少的值
     * @param def key不存在时的默认值
     * @param exp 过期时间，单位是秒，-1表示不过期
     */
    public long decr(String key, int by, long def, int exp) throws IOException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            long decr = memcachedClient.decr(key, by, def, exp);
            return decr;
        } finally {
            memcachedClient.shutdown();
        }
    }

    /**
     * 删除缓存
     *
     * @param key 缓存key
     */
    public Boolean delete(String key) throws IOException, ExecutionException, InterruptedException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            OperationFuture<Boolean> deleteFuture = memcachedClient.delete(key);
            return deleteFuture.get();
        } finally {
            memcachedClient.shutdown();
        }
    }

    /**
     * 刷新所有缓存
     *
     * @param delay 延迟时间，单位是秒，-1表示不延时
     */
    public Boolean flush(int delay) throws IOException, ExecutionException, InterruptedException {
        MemcachedClient memcachedClient = getMemcachedClient();
        try {
            OperationFuture<Boolean> delayFuture = memcachedClient.flush(delay);
            return delayFuture.get();
        } finally {
            memcachedClient.shutdown();
        }
    }
}
